package events

import (
	"strings"
	"time"
	"github.com/jinzhu/gorm"
	"meman/sys/basic"
	"strconv"
)

const (
	TABLE_BROADCAST_LOG = "broadcast_failure_log"

	JOIN_LOG_And_SUBSCRIBERS = " JOIN subscribers sub ON sub.subscriber_id = log.subscriber_id "
	JOIN_LOG_And_MSGCLASSES = " JOIN message_classes msg_class ON msg_class.class_id = log.message_class_id "
	JOIN_LOG_And_SUBSCRIPTIONS = " JOIN subscriptions subs on subs.subscription_id = log.subscription_id "
)

/**
日志
mysql decimal 类型在go中为float64
 */
type Log struct {
	LogId int `gorm:"primary_key;AUTO_INCREMENT;column:log_id"`
	MessageClassId int `gorm:"column:message_class_id"`
	SubscriberId int `gorm:"column:subscriber_id"`
	Time int64  `gorm:"column:time"`
	MessageBody string `gorm:"column:message_body"`
	RetryTimes int `gorm:"column:retry_times"`
	LastRetryTime int64 `gorm:"column:last_retry_time"`
	LastFailureMessage string `gorm:"column:last_failure_message"`
	FinalStatus int `gorm:"column:final_status"`
	FirstFailureMessage string `gorm:"column:first_failure_message"`
	JobId string `gorm:"column:job_id"`
	Alive int `gorm:"column:alive"`
	MessageTime float64 `gorm:"column:message_time"`
	SubscriptionId int `gorm:"column:subscription_id"`
	LastTarget string `gorm:"column:last_target"`

}
/**
gin使用checkbox获取值失败,需要自己定义一个struct 进行转
 */
type LogIds struct {
	LogIds []string `form:"log_id[]"`
}

type LogResult struct {
	LogId int `gorm:"primary_key;AUTO_INCREMENT;column:log_id"`
	MessageClassId int `gorm:"column:message_class_id"`
	SubscriberId int `gorm:"column:subscriber_id"`
	Time int64  `gorm:"column:time"`
	MessageBody string `gorm:"column:message_body"`
	RetryTimes int `gorm:"column:retry_times"`
	LastRetryTime int64 `gorm:"column:last_retry_time"`
	LastFailureMessage string `gorm:"column:last_failure_message"`
	FinalStatus int `gorm:"column:final_status"`
	FirstFailureMessage string `gorm:"column:first_failure_message"`
	JobId string `gorm:"column:job_id"`
	Alive int `gorm:"column:alive"`
	MessageTime float64 `gorm:"column:message_time"`
	SubscriptionId int `gorm:"column:subscription_id"`
	LastTarget string `gorm:"column:last_target"`

	//Subscriber
	SubscriberKey string `gorm:"column:subscriber_key"`
	SubscriberName string `gorm:"column:subscriber_name"`

	//message_class
	ClassKey string `gorm:"column:class_key"`
	ClassName string `gorm:"column:class_name"`
	Comment string  `gorm:"column:comment"`

	//subscription
	Timeout int `gorm:"column:timeout"`
	SubscribeTime int64 `gorm:"column:subscribe_time"`
	Status int `gorm:"column:status"`

	//是否可恢复
	CanbeRestored bool

}


/**
获取日志列表
@param conds map[string]interface{} where语句参数
@param page int  当前页码
@param pageSize int  每页有几个数据
@return []Message,count  返回消息数组,和一共有多少条数据
 */
func (l *Log) GetLogList(db *gorm.DB,conds map[string]interface{}, page, perPageNums int) ([]LogResult, error){
	start := GetPageStart(page, perPageNums)
	limit := "limit "+ strconv.Itoa(start) + ", " + strconv.Itoa(perPageNums)

	whereSql, value := buildWhere(conds)

	sql := "select log.*, sub.subscriber_key, sub.subscriber_name, msg_class.class_name, msg_class.class_key, msg_class.comment from ( " +
		" SELECT log.log_id, log.time, log.retry_times, log.last_retry_time, log.final_status, log.alive, log.message_time, " +
		"log.subscriber_id, log.message_class_id, log.job_id FROM broadcast_failure_log log " +
		JOIN_LOG_And_SUBSCRIBERS + JOIN_LOG_And_MSGCLASSES +
		whereSql + " ORDER  BY `time` desc " + limit + " ) log " +
		JOIN_LOG_And_SUBSCRIBERS + JOIN_LOG_And_MSGCLASSES +
		" order by log.`time` desc"


	var LogResults []LogResult
	err := db.Raw(sql, value...).Scan(&LogResults).Error

	return LogResults, err
}


func (l *Log) Count(conds map[string]interface{}) (*gorm.DB, int64){
	var count int64
	db := basic.Read()

	sql := "select count(1) count from " +TABLE_BROADCAST_LOG + " log " + JOIN_LOG_And_SUBSCRIBERS + " " + JOIN_LOG_And_MSGCLASSES
	whereSql, params := buildWhere(conds)
	sql = sql + whereSql

	rows := db.Raw(sql, params...).Row()
	rows.Scan(&count)

	return db, count
}

func (l *Log) GetLogDetail(id int) (LogResult, error)  {
	db := basic.Write()
	sql := "select log.log_id, log.time, log.retry_times, log.message_body, log.job_id,log.subscriber_id, " +
	"log.message_class_id,log.last_retry_time, log.final_status, log.alive, log.first_failure_message, " +
	"log.last_failure_message, log.message_time, log.last_target, sub.`subscriber_key`, sub.subscriber_name, " +
	"msg_class.class_name, msg_class.class_key, msg_class.comment, subs.subscription_id, subs.timeout, " +
	"subs.subscribe_time, subs.status from " + TABLE_BROADCAST_LOG + " log " +
	JOIN_LOG_And_SUBSCRIBERS + JOIN_LOG_And_MSGCLASSES + JOIN_LOG_And_SUBSCRIPTIONS +
	" where log_id = " + strconv.Itoa(id)

	var LogResults LogResult
	err := db.Raw(sql).Scan(&LogResults).Error

	return LogResults, err

}


func buildWhere(conds map[string]interface{}) (string, []interface{}) {

	var prepareWhere []string
	var value []interface{}

	//如果不存在这两个值
	timeNow := time.Now()
	if _,ok := conds["first_push_time_start"]; !ok {
		conds["first_push_time_start"] = time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 0, 0, 0, 0, time.Local).Unix()
	}
	if _,ok := conds["first_push_time_end"]; !ok {
		conds["first_push_time_end"] = time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 23, 59, 59, 0, time.Local).Unix()
	}
	
	for k, v := range  conds  {
		if k == "first_push_time_start" {
			prepareWhere  = append(prepareWhere, "time >= ?")
		} else if k == "first_push_time_end" {
			prepareWhere  = append(prepareWhere, "time <= ?")
		}else {
			prepareWhere  = append(prepareWhere, k + " = ?")
		}
		value = append(value, v)

	}

	whereSql := " where " + strings.Join(prepareWhere, " AND ")

	return whereSql, value
}

func quoteString(val string) string {
	return "`" + strings.Trim(val, "`") + "`"
}

/**
再消息重新进入队列后重置重复次数.
@param int logId
@return err
*/
func (l *Log) ResetRetryTimes(id int) error {
	db := basic.Write()
	err := db.Table(TABLE_BROADCAST_LOG).Where("log_id = ?", id).Updates(Log{RetryTimes:0, Alive:1}).Error
	return err
}

func (l *Log) CanbeRestored(log LogResult) (bool,error) {
	//id,err :=strconv.Atoi(log.JobId)
	//if err != nil {
	//	return false, err
	//}

	if log.Alive != 0 || log.FinalStatus != 0 || len(log.JobId) <=0 {
		return false, nil
	}
	return true, nil
}


